/*******************************************
 * Copyright 2007 Aphrodite Framework for javaME .
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * Email : owner@aphroditeme.dev.java.net
 * Contributors:
 *     Kent Elton - initial API and implementation
 *******************************************/

package com.aphrodite.io;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.microedition.io.HttpConnection;

/**
 * <p>
 * Upload a file over HTTP
 * </p>
 * 
 * <b>Uploading a file over HTTP</b></br> <code>
 * HttpUpload flleUpload=new HttpUpload(getFileBytes(),"userImage","avatar.png","image/png");<br/>
 * fileUpload.addHttpParamter("userID","testuser");<br/>
 * fileUpload.upload("http://myserver.com/user/readAvatar",true);<br/>
 * while(!fileUpload.uploadComplete()){<br/>
 * ... wait for the upload to complete<br/>
 * }<br/>
 * System.out.println("Response"+new String(fileUpload.getResponse());<br/>
 * </code>
 * 
 * @author kentelt
 * 
 */
public class HttpUpload {

	final static String boundary = "----------V2ymHFg03ehbqgZCaKO6jy";
	private byte[] data;
	private final String exception = "Cannot complete request during upload";
	private String fileName;
	private String fileType;
	private String formFieldName;
	/* indicates that the file upload is in progress */
	private boolean inProgress;
	private Hashtable params = new Hashtable();

	private boolean processComplete;

	private byte[] response;

	/**
	 * 
	 * @param data
	 *            The file to be sent to the server
	 * @param formField
	 *            Name of the form field representing the file
	 * @param fileName
	 * @param fileType
	 *            in MIME representation. <i>image/png</i> for instance.
	 */
	public HttpUpload(byte[] data, String formField, String fileName, String fileType) {
		this.data = data;
		this.formFieldName = formField;
		this.fileName = fileName;
		this.fileType = fileType;
	}

	/**
	 * Add a HTTP paramter to the upload
	 * 
	 * @param name
	 * @param value
	 */
	public void addHttpParameter(String name, String value) {
		if (!inProgress) {
			params.put(name, value);
		} else
			throw new IllegalStateException(exception);

	}

	private byte[] getBoundaryMessage() {

		StringBuffer buf = new StringBuffer("--").append(boundary).append("\r\n");
		Enumeration keys = params.keys();
		while (keys.hasMoreElements()) {
			String key = (String) keys.nextElement();
			String value = (String) params.get(key);

			buf.append("Content-Disposition: form-data; name=\"").append(key).append("\"\r\n").append("\r\n").append(
					value).append("\r\n").append("--").append(boundary).append("\r\n");
		}
		buf.append("Content-Disposition: form-data; name=\"").append(formFieldName).append("\"; filename=\"").append(
				fileName).append("\"\r\n").append("Content-Type: ").append(fileType).append("\r\n\r\n");

		return buf.toString().getBytes();
	}

	private byte[] getDataToWrite() {
		String endBoundary = "\r\n--" + boundary + "--\r\n";
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		byte[] binary = null;
		try {
			bos.write(getBoundaryMessage());
			bos.write(data);
			bos.write(endBoundary.getBytes());
			binary = bos.toByteArray();
			System.out.println("[HttpUpload.getDataToWrite] Data length: " + binary.length);
			bos.close();
		} catch (java.io.IOException e) {
			System.out.println("[HttpUpload.upload] Error  construction POST data" + e.toString());
			e.printStackTrace();
		}
		return binary;
	}

	/**
	 * 
	 * @return
	 * @see HttpUpload.uploadComplete
	 */
	public byte[] getResponse() {
		return response;
	}

	public void setFileName(String name) {
		if (!inProgress) {
			fileName = name;
		} else
			throw new IllegalStateException(exception);
	}

	public void setFormField(String formField) {
		this.formFieldName = formField;
	}

	/**
	 * upload the file to the specified URL
	 * 
	 * @param url
	 */
	public void upload(final String url, final boolean readResponse) {
		if (!inProgress) {
			processComplete = false;
			final byte[] toWrite = getDataToWrite();
			(new Thread() {
				public void run() {
					javax.microedition.io.HttpConnection hc = null;
					java.io.InputStream is = null;
					inProgress = true;
					try {
						hc = (javax.microedition.io.HttpConnection) javax.microedition.io.Connector.open(url);
						hc.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
						hc.setRequestMethod(HttpConnection.POST);
						OutputStream dout = hc.openOutputStream();
						dout.write(toWrite);
						dout.close();
						if (readResponse) {
							ByteArrayOutputStream bos = new ByteArrayOutputStream();
							int ch;
							is = hc.openInputStream();
							while ((ch = is.read()) != -1) {
								bos.write(ch);
							}
							response = bos.toByteArray();
							bos.close();
						}

					} catch (java.io.IOException e) {
						System.out.println("[HttpUpload.upload] Exception during upload " + e.toString());
						e.printStackTrace();
					} finally {
						try {
							is.close();
							hc.close();
						} catch (IOException e) {
							e.printStackTrace();
						}

					}
					inProgress = false;
					processComplete = true;
				}
			}).start();
		}
	}

	public boolean uploadComplete() {
		return processComplete;
	}
}
